/** 
Copyright (c) 2010, Sheikh Abdul Wahid Ahmed
Details @ http://extremecodeworld.codeplex.com/license
**/

using System;
using System.Data;
using System.Configuration;
using System.Web;
using System.Collections.Generic;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
using EXtremecode.BusinessLayer;
using EXtremecode.PresentationLayer;
using EXtremecode.Utils;
using EXtremecode.Common;
using System.Text;
using System.IO;
using EXtremecode.Logging;
using EXtremecode.DataAccessLayer;
/// <summary>
/// Summary description for ParentPage
/// </summary>
namespace EXtremecode.PresentationLayer
{

    public class ListParentPage : ParentPage
    {
        public delegate void OnSelectedRowActionDelegate(string actionName, DataKey key);
        public delegate void OnSelectedRowsActionCompleteDelegate(string actionName);
        public delegate void OnSelectedRowsActionFailedDelegate(string actionName);

        protected readonly int SelectCheckBoxColumnIndex = 0;
        protected readonly int SerialNumColumnIndex = 1;
        protected int ActionButtonsColumnIndex = -1;

        private IListPage listPage;
        protected event OnSelectedRowActionDelegate OnSelectedRowAction;
        protected event OnSelectedRowsActionCompleteDelegate OnSelectedRowsActionComplete;
        protected event OnSelectedRowsActionFailedDelegate OnSelectedRowsActionFailed;




        public enum ExportFormat
        {
            Excel, Word, Html
        };

        public ListParentPage()
            : base()
        {
            if (!(this is IListPage))
            {
                throw new Exception("ListPage should implement IListPage interface");
            }
            listPage = this as IListPage;
        }
        private string sortExpressionSource = string.Empty;
        protected List<Pair> FilterPair
        {
            get
            {
                if (ViewState["FilterPair"] == null)
                {
                    ViewState["FilterPair"] = new List<Pair>();
                }
                return ViewState["FilterPair"] as List<Pair>;
            }

        }

        
        protected string[] ReturnKey
        {
            get
            {
                string[] returnKey = new string[0];
                if (Request.QueryString["ReturnKey"] != null)
                {
                    returnKey = Request.QueryString["ReturnKey"].Split(',');
                }
                else
                {
                    if (listPage.Grid.DataKeyNames != null)
                    {
                        returnKey = listPage.Grid.DataKeyNames;
                    }

                }
                return returnKey;
            }
        }

        protected bool IsRowSelectionPopup
        {
            get
            {
                return (Request.QueryString["SelectionPopup"] == "0")? false: true&IsPopup;
            }
        }

        protected bool IsMultiRowSelectionAllowed
        {
            get
            {
                return (Request.QueryString["MultiRowSelectionAllowed"] == "0") ? false : true;
            }
        }

        protected string OpenerReturnValueHandler
        {
            get
            {
                string openerHandler = string.Empty;
                if (Request.QueryString["OpenerHandler"] != null)
                {
                    openerHandler = Request.QueryString["OpenerHandler"].ToString();
                }
                else
                {
                    openerHandler = "OnPopupValueReturn_" + string.Join("_", ReturnKey);
                }
                return openerHandler;
            }
        }

        public override void VerifyRenderingInServerForm(Control control)
        {
            //--Override VerifyRenderingInServerForm to suppress error which is generated while rendering.
            //I have wasted max 5 hours to find this solution.
        }
        protected override void OnPreInit(EventArgs e)
        {
            base.OnPreInit(e);
            OnInitMethod(null);
        }
        protected override void OnInit(EventArgs e)
        {
            //event are not persisted by viewstate.need to call in each trip to server.
            if (listPage.Pager != null)
            {
                listPage.Pager.PageLinkClick += new PageLinkClickDelegate(Pager_PageLinkClick);
            }
            listPage.Grid.RowCommand += new GridViewCommandEventHandler(Grid_RowCommand);
            listPage.Grid.RowCreated += new GridViewRowEventHandler(Grid_RowCreated);
            listPage.Grid.RowDataBound += new GridViewRowEventHandler(Grid_RowDataBound);
            listPage.Grid.DataBound += new EventHandler(Grid_DataBound);
            //listPage.Grid.Columns.FieldsChanged += new EventHandler(GridColumns_FieldsChanged);

            ActionButtonsColumnIndex = listPage.Grid.Columns.Count - 1; //last column
            base.OnInit(e);
        }

        void GridColumns_FieldsChanged(object sender, EventArgs e)
        {
            ActionButtonsColumnIndex = listPage.Grid.Columns.Count - 1; //last column
        }
        protected void OnInitMethod(EventArgs e)
        {
            

            if (!Page.IsPostBack)
            {
                if (Request.QueryString["Filter"] != null && Request.QueryString["Filter"] == "1")
                {
                    //if url holding filter, then refresh session with this filter,
                    BusinessObjectCollection boCol = GetBOCollectionForList();
                    boCol.Refresh();

                    foreach (string key in Request.QueryString.AllKeys)
                    {
                        //all keys start with [f_] which are holding search critaria.
                        bool isCritariaFld = false;//if field is trimed, means it is critaria fld.
                        string fieldName = StringProcessor.LeftTrim(key, "f_", out isCritariaFld);
                        if (isCritariaFld)
                        {
                            boCol[fieldName] = Request.QueryString[key];
                        }
                    }

                    if (Request.QueryString["GroupFilterFields"] != null && Request.QueryString["GroupFilterValues"] != null)
                    {
                        string[] groupFilterFields = Request.QueryString["GroupFilterFields"].Split(',');
                        string[] groupFilterValues = Request.QueryString["GroupFilterValues"].Split(',');

                        if (groupFilterFields.Length != groupFilterValues.Length)
                        {
                            //invalid group filter
                            throw Logger.Write(new Exception("groupFilter is invalid"));
                        }

                        for (int i = 0; i < groupFilterFields.Length; i++)
                        {
                            boCol[groupFilterFields[i]] = groupFilterValues[i];
                        }
                    }
                }

            }

            
            
        }



        protected override void OnLoad(EventArgs e)
        {



            if (!Page.IsPostBack)
            {
                //populate search panel.
                listPage.PopulateSearchPanel();

                //Populate Pager
                PopulatePager();

                //bind grid
                BindData();
            }

            //add java script for applying style of selected rows
            Page.ClientScript.RegisterStartupScript(typeof(string), "ApplySelectRowsStyle",
                string.Format("ApplySelectRowsStyle(document.getElementById('{0}'));", listPage.Grid.ClientID)
                , true);


            //for returning seleted rows.
            IASCXButton btnRetunRowsKeys = FindControlRecursive("btnRetunRowsKeys") as IASCXButton;
            if (IsRowSelectionPopup && btnRetunRowsKeys != null)
            {
                btnRetunRowsKeys.Visible = true;
                btnRetunRowsKeys.OnClientClick =
                    string.Format("if (!InTableApplyCheckboxSelectionChecks(document.getElementById('{0}'))) return false;"
                            , listPage.Grid.ClientID) +

                    string.Format("opener.{0}(GetSelectedCheckBoxTagValues(" +
                     "document.getElementById('{1}'),'ReturnKeyValue'));window.close();", OpenerReturnValueHandler, listPage.Grid.ClientID);



            }


            base.OnLoad(e);
        }

        protected override void OnPreRender(EventArgs e)
        {
            if (IsRowSelectionPopup)
            {
                if (SelectCheckBoxColumnIndex >= 0)
                {
                    if (!IsMultiRowSelectionAllowed)
                    {
                        listPage.Grid.Columns[SelectCheckBoxColumnIndex].Visible = false;
                    }
                }
                if (ActionButtonsColumnIndex >= 0)
                {
                    listPage.Grid.Columns[ActionButtonsColumnIndex].Visible = false;
                }
            }
            base.OnPreRender(e);
        }


        private void PopulatePager()
        {
            if (listPage.Pager != null)
            {
                BusinessObjectCollection col = GetBOCollectionForList();
                listPage.Pager.NumberOfDisplayPages = Provider.NumberOfDisplayPages;
                listPage.Pager.PageSizesList = Provider.PageSizesList;
                listPage.Pager.PageSize = col.PageSize;
                listPage.Pager.TotalRecords = col.GetRecordCount();
                listPage.Pager.CurrentPageNumber = col.PageNumber;

            }

        }



        protected BusinessObjectCollection GetBOCollectionForList()
        {
            BusinessObjectCollection col =
                SessionRepository.Instance["BOColList_" + PageKey] as BusinessObjectCollection;
            if (col == null)
            {
                col = listPage.BOCollection;
                col.AutoRefresh = false;

                SessionRepository.Instance["BOColList_" + PageKey] = col;
            }
            return col;

        }


        protected virtual void BindData()
        {
            BusinessObjectCollection col = GetBOCollectionForList();
            try
            {
                GridView gv = listPage.Grid;
                gv.DataSource = col.FillDataTable();
                gv.DataBind();
            }
            catch (Exception ex)
            {
                throw Logger.Write(ex);
            }
            finally
            {
                col.Close();
            }
        }
        protected void SortData(IButtonControl ctrlSortExpressionSource)
        {
            if (ctrlSortExpressionSource != null &&
                !string.IsNullOrEmpty(ctrlSortExpressionSource.CommandArgument))
            {
                BusinessObjectCollection col = GetBOCollectionForList();

                if (ctrlSortExpressionSource.CommandArgument == col.SortedBy)
                {
                    col.IsSortingTypeAscending = !col.IsSortingTypeAscending;
                }
                col.SortedBy = ctrlSortExpressionSource.CommandArgument;
                sortExpressionSource = (ctrlSortExpressionSource as Control).ID; //For using in decoration
                BindData();

                //As binding of data girdview generate all the rows and cells again, so we cant decorate.
                //header here. we need to place expression source name into member variable to make it further
                //usable.
            }
        }


        private static Control GetSortExpressionSourceByRecursion(Control parentControl, string sortedBy)
        {
            foreach (Control ctrl in parentControl.Controls)
            {
                IButtonControl ibc = ctrl as IButtonControl;
                if (ibc != null && ibc.CommandArgument == sortedBy && ibc.CommandName == "Sort")
                {
                    return ctrl;
                }
                else
                {
                    Control c = GetSortExpressionSourceByRecursion(ctrl, sortedBy);
                    if (c != null)
                    {
                        return c;
                    }
                }
            }

            return null;
        }
        protected void DecorateHeaderSortColumn(Control rowControl)
        {
            BusinessObjectCollection col = GetBOCollectionForList();
            Control ctrlSortExpressionSource = null;
            if (!string.IsNullOrEmpty(sortExpressionSource))
            {
                ctrlSortExpressionSource = rowControl.FindControl(sortExpressionSource);
            }
            else if (!string.IsNullOrEmpty(col.SortedBy))
            {
                ctrlSortExpressionSource = GetSortExpressionSourceByRecursion(rowControl, col.SortedBy);
            }


            if (ctrlSortExpressionSource != null)
            {

                Image img = new Image();
                img.SkinID = (col.IsSortingTypeAscending) ? "sortUp" : "sortDown";
                ctrlSortExpressionSource.Parent.Controls.Add(img);

            }


        }

        void Pager_PageLinkClick(PageLinkClickEventArgs e)
        {
            BusinessObjectCollection col = GetBOCollectionForList();
            col.PageNumber = e.PageNumber;
            col.PageSize = e.PageSize;

            BindData();

        }

        protected void Grid_RowCreated(object sender, GridViewRowEventArgs e)
        {
            switch (e.Row.RowType)
            {

                case DataControlRowType.DataRow:
                    e.Row.ID = e.Row.RowIndex.ToString();

                    //onRowSelection
                    e.Row.Attributes.Add("onmouseover", "ApplySelectRowStyle(this,true);");
                    e.Row.Attributes.Add("onmouseout", "ApplySelectRowStyle(this,false);");


                    //edit button
                    ImageButton btnEdit = e.Row.FindControl("btnEdit") as ImageButton;
                    btnEdit.CommandArgument = e.Row.RowIndex.ToString();

                    //delete button
                    ImageButton btnDelete = e.Row.FindControl("btnDelete") as ImageButton;
                    btnDelete.CommandArgument = e.Row.RowIndex.ToString();

                    //check box [select]
                    CheckBox chkSelect = e.Row.FindControl("chkSelect") as CheckBox;
                    chkSelect.InputAttributes.Add("selectCheckBox", "true");
                    chkSelect.InputAttributes.Add("onclick",
                        string.Format("var row = document.getElementById('{0}');row.checked=this.checked;ApplySelectRowStyle(row,this.checked);",
                        listPage.Grid.ClientID + "_" + e.Row.ID));
                    break;

                case DataControlRowType.Header:
                    CheckBox chkSelectAll = e.Row.FindControl("chkSelectAll") as CheckBox;
                    chkSelectAll.InputAttributes.Add("onclick",
                        string.Format("InTableCheckAll(this,document.getElementById('{0}'));", listPage.Grid.ClientID));

                    DecorateHeaderSortColumn(e.Row);
                    //we can place decoration logic in RowDataBound method, but the problem is, OnRowDataBound Event
                    //is fired only in the case of binding.
                    break;

            }


        }
        void Grid_RowDataBound(object sender, GridViewRowEventArgs e)
        {
            switch (e.Row.RowType)
            {
                case DataControlRowType.DataRow:
                    DataRowView drv = e.Row.DataItem as DataRowView;

                    //serial num [display]
                    Label lblSerialNum = e.Row.FindControl("lblSerialNum") as Label;

                    int pageSize = 0;
                    int currentPageNumber = 1;
                    if (GetBOCollectionForList().UsePaging)
                    {
                        pageSize = listPage.Pager.PageSize;
                        currentPageNumber = listPage.Pager.CurrentPageNumber;
                    }

                    lblSerialNum.Text = (e.Row.RowIndex + (pageSize * (currentPageNumber - 1)) + 1).ToString("N0");

                    //serial num [hidden field]
                    HiddenField hdnSerialNum = e.Row.FindControl("hdnSerialNum") as HiddenField;
                    hdnSerialNum.Value = e.Row.RowIndex.ToString();


                    //make return key.
                    if (IsRowSelectionPopup)
                    {
                        string returnKeyValue = string.Empty;
                        string qoma = string.Empty;
                        string[] returnKey = ReturnKey;
                        for (int i = 0; i < returnKey.Length; i++)
                        {
                            returnKeyValue += qoma +
                                  ((drv[returnKey[i]] != DBNull.Value) ?
                                    drv[returnKey[i]].ToString() :
                                    string.Empty);
                            qoma = ",";
                        }

                        e.Row.Attributes.Add("ReturnKeyValue", returnKeyValue);
                        e.Row.Attributes.Add("style", "cursor:hand;");
                        CheckBox chkSelect = e.Row.FindControl("chkSelect") as CheckBox;
                        chkSelect.InputAttributes.Add("ReturnKeyValue", returnKeyValue);

                        if (!IsMultiRowSelectionAllowed)
                        {
                            for (int cellIndex = 0; cellIndex < e.Row.Cells.Count; cellIndex++)
                            {
                                if (cellIndex == SelectCheckBoxColumnIndex)
                                {
                                    continue;
                                }

                                e.Row.Cells[cellIndex].Attributes.Add("onclick", string.Format("opener.{0}('{1}');window.close()",
                                    OpenerReturnValueHandler, returnKeyValue));
                            }
                        }

                    }

                    break;

                case DataControlRowType.Header:
                    break;

            }
        }

        protected void Grid_RowCommand(object sender, GridViewCommandEventArgs e)
        {

            if (e.CommandName == "Sort")
            {

                //reset page number.
                BusinessObjectCollection col = GetBOCollectionForList();
                if (col.UsePaging)
                {
                    col.PageNumber = 1;
                    listPage.Pager.CurrentPageNumber = 1;
                }

                Control ctrl = e.CommandSource as Control;
                SortData(e.CommandSource as IButtonControl);
            }
            else if (e.CommandName == "SelectedAction" &&
                e.CommandArgument != null && e.CommandArgument.ToString() != string.Empty)
            {
                try
                {
                    bool actionPerformed = false;
                    foreach (GridViewRow dvr in listPage.Grid.Rows)
                    {
                        DataKey key = GetDataKeyIfSelected(listPage.Grid, dvr.RowIndex, e.CommandArgument.ToString());
                        if (key != null)
                        {
                            if (OnSelectedRowAction != null)
                            {
                                OnSelectedRowAction(e.CommandArgument.ToString(), key);
                                actionPerformed = true;
                            }
                        }

                    }
                    if (actionPerformed && OnSelectedRowsActionComplete != null)
                    {
                        OnSelectedRowsActionComplete(e.CommandArgument.ToString());
                    }
                    else
                    {
                        Information = ResourceProvider.GetGeneralResourceString("Message_NoAction"); 
                    }

                }
                catch (Exception ex)
                {
                    if (OnSelectedRowsActionFailed != null)
                    {
                        OnSelectedRowsActionFailed(e.CommandArgument.ToString());
                    }

                }
            }

        }

        public void Grid_DataBound(object sender, EventArgs e)
        {
            GridView grid = listPage.Grid;
            MultiView mvSearchResult = listPage.MVSearchResult;
            if (mvSearchResult != null)
            {
                if (grid.Rows.Count == 0)
                {
                    View viewNoRecodFound = mvSearchResult.FindControl("viewNoRecodFound") as View;
                    mvSearchResult.SetActiveView(viewNoRecodFound);
                }
                else
                {
                    View viewRecordsFound = mvSearchResult.FindControl("viewRecordsFound") as View;
                    mvSearchResult.SetActiveView(viewRecordsFound);
                }
            }
        }

        protected void ExportListTo(ExportFormat format)
        {


            string contentType = string.Empty;
            string contentDisposition = string.Empty;
            switch (format)
            {
                case ExportFormat.Excel:
                    contentType = "application/vnd.ms-excel";
                    contentDisposition = "attachment; filename=\"Report.xls\"";
                    break;

                case ExportFormat.Word:
                    contentType = "application/vnd.ms-word";
                    contentDisposition = "attachment; filename=\"Report.doc\"";
                    break;
            }


            Response.Clear();
            Response.ContentType = contentType;
            Response.AddHeader("Content-Disposition", contentDisposition);

            //***get template
            StringBuilder sb = FileUtil.ReadFileData(Provider.ExportTemplateFilePath);
            UCPair[] parts = StringProcessor.SplitStringIntoDefinedParts(sb.ToString());
            //first:Type and second:Data
            foreach (UCPair part in parts)
            {
                if (part.First.ToString() == "Content")
                {
                    Response.Write(part.Second);
                }
                else if (part.First.ToString() == "Process")
                {
                    string process = part.Second.ToString();

                    switch (process)
                    {
                        case "StyleSheet":
                            StringBuilder sbStyleSheet = FileUtil.ReadFileData(Provider.ExportStyleSheetPath);
                            Response.Write(sbStyleSheet.ToString());
                            break;

                        case "Title":
                            Response.Write(listPage.Title);
                            break;

                        case "Filter":
                            if (FilterPair.Count > 0)
                            {
                                Table tbl = GetFilterPairTable(FilterPair);
                                tbl.RenderControl(new HtmlTextWriter(Response.Output));
                            }
                            break;

                        case "Grid":
                            //for getting grid data need to bind it first.
                            //as we are wanting to get allrecords so disable paging.
                            BusinessObjectCollection col = GetBOCollectionForList();
                            int currentPageNumber = col.PageNumber;
                            col.PageNumber = 0; //paging disabled
                            try
                            {
                                BindData();
                            }
                            finally
                            {
                                col.PageNumber = currentPageNumber;
                            }

                            //get grid data.
                            //make columns invisible which should not be appeared in exported result.
                            bool selectCheckBoxColumnVisiblity = false;
                            bool serialNumberColumnVisiblity = false;
                            bool actionBottonsColumnVisiblity = false;
                            if (SelectCheckBoxColumnIndex >= 0)
                            {
                                selectCheckBoxColumnVisiblity = listPage.Grid.Columns[SelectCheckBoxColumnIndex].Visible;
                                listPage.Grid.Columns[SelectCheckBoxColumnIndex].Visible = false;
                            }
                            if (ActionButtonsColumnIndex >= 0)
                            {
                                actionBottonsColumnVisiblity = listPage.Grid.Columns[ActionButtonsColumnIndex].Visible;
                                listPage.Grid.Columns[ActionButtonsColumnIndex].Visible = false;
                            }

                            //render grid.
                            try
                            {
                                PrepareGridViewForExport(listPage.Grid);
                                listPage.Grid.RenderControl(new HtmlTextWriter(Response.Output));

                            }
                            finally
                            {
                            }

                            break;
                    }
                }
            }
            Response.Flush();

        }

        private static void PrepareGridViewForExport(Control gv)
        {
            Literal l = new Literal();
            string name = String.Empty;
            for (int i = 0; i < gv.Controls.Count; i++)
            {
                if (gv.Controls[i].Visible)
                {
                    if (gv.Controls[i].GetType() == typeof(LinkButton))
                    {
                        l.Text = (gv.Controls[i] as LinkButton).Text;
                        gv.Controls.Remove(gv.Controls[i]);
                        gv.Controls.AddAt(i, l);
                    }
                    else if (gv.Controls[i].GetType() == typeof(DropDownList))
                    {
                        l.Text = (gv.Controls[i] as DropDownList).SelectedItem.Text;
                        gv.Controls.Remove(gv.Controls[i]);
                        gv.Controls.AddAt(i, l);
                    }
                    else if (gv.Controls[i].GetType() == typeof(CheckBox))
                    {
                        l.Text = (gv.Controls[i] as CheckBox).Checked ? "True" : "False";
                        gv.Controls.Remove(gv.Controls[i]);
                        gv.Controls.AddAt(i, l);
                    }

                    else if (gv.Controls[i].GetType() == typeof(HyperLink))
                    {
                        if (gv.Controls[i].Controls.Count == 0)
                        {
                            l.Text = (gv.Controls[i] as HyperLink).Text;
                            gv.Controls.Remove(gv.Controls[i]);
                            gv.Controls.AddAt(i, l);
                        }
                    }
                    else if (gv.Controls[i].GetType() == typeof(Image))
                    {
                        if (gv.Controls[i].Parent.GetType() == typeof(DataControlFieldHeaderCell))
                            gv.Controls.Remove(gv.Controls[i]);
                    }
                    else if (gv.Controls[i].GetType() == typeof(HiddenField))
                    {
                        gv.Controls.Remove(gv.Controls[i]);
                    }
                    if (i < gv.Controls.Count && gv.Controls[i].HasControls())
                    {
                        PrepareGridViewForExport(gv.Controls[i]);
                    }
                }
            }
        }

        private static Table GetFilterPairTable(List<Pair> filterPair)
        {
            Table tbl = new Table();
            tbl.BorderWidth = Unit.Pixel(0);
            tbl.CellPadding = 0;
            tbl.CellSpacing = 0;
            tbl.Width = Unit.Percentage(100);

            int pairsInEachRow = 2;
            int index = 0;
            bool rowNeedToBeAdded = false;
            TableRow tblRow = new TableRow(); //first row initialized.
            foreach (Pair pair in filterPair)
            {
                index++;

                //createPair of cell.
                TableCell tblCellLabel = new TableCell();
                TableCell tblCellValue = new TableCell();
                tblCellLabel.Width = Unit.Pixel(80);
                tblCellValue.Width = Unit.Pixel(150);

                tblCellLabel.Text = pair.First.ToString() + ":";
                tblCellValue.Text = pair.Second.ToString();
                tblRow.Cells.Add(tblCellLabel);
                tblRow.Cells.Add(tblCellValue);

                if (index == 1 || pairsInEachRow % index != 0)
                {
                    rowNeedToBeAdded = true;

                    //add seperator.
                    TableCell tblCellSeperator = new TableCell();
                    tblCellValue.Width = Unit.Pixel(80);
                    tblRow.Cells.Add(tblCellSeperator);
                }
                else
                {
                    tbl.Rows.Add(tblRow);
                    tblRow = new TableRow(); //for next itration
                    rowNeedToBeAdded = false;
                }


            }

            if (rowNeedToBeAdded)
            {
                tbl.Rows.Add(tblRow);
            }


            return tbl;

        }

        protected static DataKey GetDataKeyIfSelected(GridView grid, int rowIndex,string commandName)
        {
            CheckBox chkSelect = grid.Rows[rowIndex].FindControl("chkSelect") as CheckBox;
            DataKey key = null;

            if (chkSelect != null && chkSelect.Checked && !string.IsNullOrEmpty(chkSelect.Attributes[commandName]))
            {
                key = grid.DataKeys[rowIndex];
            }
            return key;
        }


    }
}